﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

using TouchSocket.Core;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;

namespace TouchRpc_Server
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Init();
            Console.ReadKey();
        }
        private static void Init()
        {
            var service = new TouchSocketConfig()//配置
            .SetListenIPHosts(new IPHost[] { new IPHost(7789) })
            .UsePlugin()
            .ConfigureContainer(a =>
            {
                a.AddConsoleLogger();
                a.AddFileLogger();
            })
            .ConfigurePlugins(a =>
            {
                a.Add<MyPlugin>();
            })
            .SetVerifyToken("File")//连接验证口令。
            .BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService，然后Setup，然后Start。
            service.Logger.Info("服务器成功启动");
        }

    }
    class MyPlugin : TouchRpcPluginBase<TcpTouchRpcSocketClient>
    {

        protected override void OnFileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e)
        {
            e.IsPermitOperation = true;//运行操作

            //有可能是上传，也有可能是下载
            client.Logger.Info($"有客户端请求传输文件，ID={client.ID}，请求类型={e.TransferType}，请求文件名={e.ResourcePath}");
        }

        protected override void OnFileTransfered(TcpTouchRpcSocketClient client, FileTransferStatusEventArgs e)
        {
            //传输结束，但是不一定成功，需要从e.Result判断状态。
            client.Logger.Info($"客户端传输文件结束，ID={client.ID}，请求类型={e.TransferType}，文件名={e.ResourcePath}，请求状态={e.Result}");
        }

        protected override void OnHandshaked(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e)
        {
            client.Logger.Info($"有客户端成功验证，ID={client.ID},准备下发文件...");
            Metadata metadata = new Metadata();//传递到服务器的元数据
            metadata.Add("1", "1");
            metadata.Add("2", "2");

            FileOperator fileOperator = new FileOperator()//实例化本次传输的控制器，用于获取传输进度、速度、状态等。
            {
                Flags = TransferFlags.BreakpointResume,//尝试断点续传，使用断点续传时，会验证MD5值
                SavePath = @"E:\test1\a.txt",//保存路径
                ResourcePath = @"E:\test\a.txt",//请求路径
                Metadata = metadata//传递到服务器的元数据
            };
            fileOperator.Timeout = TimeSpan.FromSeconds(60);//当传输大文件，且启用断点续传时，服务器可能会先计算MD5，而延时响应，所以需要设置超时时间。

            //此处的作用相当于Timer，定时每秒输出当前的传输进度和速度。
            LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
            {
                if (fileOperator.Result.ResultCode != ResultCode.Default)
                {
                    loop.Dispose();
                }

                client.Logger.Info($"进度：{fileOperator.Progress}，速度：{fileOperator.Speed()}");
            });

            loopAction.RunAsync();



            //此方法会阻塞，直到传输结束，也可以使用PullFileAsync
            IResult result = client.PushFile(fileOperator);

            client.Logger.Info(result.ToString());
        }

        protected override void OnDisconnected(TcpTouchRpcSocketClient client, ClientDisconnectedEventArgs e)
        {
            client.Logger.Info($"有客户端断开，ID={client.ID}");
            base.OnDisconnected(client, e);
        }
        /// <summary>
        /// 获取所有文件
        /// </summary>
        /// <returns></returns>
        private List<string> getAllFiles(string dir)
        {
            List<string> FilesList = new List<string>();
            DirectoryInfo fileDire = new DirectoryInfo(dir);
            if (!fileDire.Exists)
            {
                throw new System.IO.FileNotFoundException("目录:" + fileDire.FullName + "没有找到!");
            }
            this.getAllDirFiles(fileDire, FilesList);
            this.getAllDirsFiles(fileDire.GetDirectories(), FilesList);
            return FilesList;
        }
        /// <summary>
        /// 获取一个文件夹下的所有文件夹里的文件
        /// </summary>
        /// <param name="dirs"></param>
        /// <param name="filesList"></param>
        private void getAllDirsFiles(DirectoryInfo[] dirs, List<string> filesList)
        {
            foreach (DirectoryInfo dir in dirs)
            {
                foreach (FileInfo file in dir.GetFiles("*.*"))
                {
                    filesList.Add(file.Name);
                }
                this.getAllDirsFiles(dir.GetDirectories(), filesList);
            }
        }

        /// <summary>
        /// 获取一个文件夹下的文件
        /// </summary>
        /// <param name="strDirName">目录名称</param>
        /// <param name="filesList">文件列表HastTable</param>
        private void getAllDirFiles(DirectoryInfo dir, List<string> filesList)
        {
            foreach (FileInfo file in dir.GetFiles("*.*"))
            {
                //filesList.Add(file.LastWriteTime);
                filesList.Add(file.Name);
            }
        }
    }

}
